/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.lib.geotools;

import java.awt.Point;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.util.ArrayList;
import java.util.List;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.geometry.BoundingBox;

/**
 *
 * @author Timon Veenstra
 */
public class CoverageTools {
    public GridCoverage2D make() {

        List<SensorData> sensorData = new ArrayList<SensorData>();
        sensorData.add(new SensorData(1, 2, 3, 4, 5, 51.2114, 3.13154));
        sensorData.add(new SensorData(2, 3, 4, 2, 1, 51.2122, 3.13354));
        sensorData.add(new SensorData(3, 4, 5, 3, 2, 51.2134, 3.13454));
        sensorData.add(new SensorData(4, 5, 6, 4, 4, 51.2164, 3.13564));
        sensorData.add(new SensorData(5, 6, 7, 45, 5, 51.2117, 3.13454));
        sensorData.add(new SensorData(6, 1, 8, 6, 7, 51.2164, 3.13254));


        double minx = sensorData.get(0).x;
        double maxx = sensorData.get(0).x;
        double miny = sensorData.get(0).y;
        double maxy = sensorData.get(0).y;

        for (SensorData sd : sensorData) {
            minx = (minx < sd.x) ? minx : sd.x;
            miny = (miny < sd.y) ? miny : sd.y;
            maxx = (maxx > sd.x) ? maxx : sd.x;
            maxy = (maxy > sd.y) ? maxy : sd.y;
        }

        // width height and ration in coordiantes
        double diffx = maxx - minx;
        double diffy = maxy - miny;
        double ratio = diffy / diffx;


        // in pixels
        Double width = Math.ceil(Math.sqrt(sensorData.size() / ratio));
        Double height = Math.ceil(Math.sqrt(sensorData.size() * ratio));

        int w = width.intValue();
        int h = height.intValue();
        int bands = 5;
        Point location = new Point(0, 0);
        WritableRaster raster = WritableRaster.createBandedRaster(DataBuffer.TYPE_INT, w, h, bands, location);


        for (SensorData sd : sensorData) {
            Double x = Math.floor((sd.x - minx) / (diffx / (width-1)));
            Double y = Math.floor((sd.y - miny) / (diffy / (height-1)));
            raster.setSample(x.intValue(), y.intValue(), 0, sd.b1);
            raster.setSample(x.intValue(), y.intValue(), 1, sd.b2);
            raster.setSample(x.intValue(), y.intValue(), 2, sd.b3);
            raster.setSample(x.intValue(), y.intValue(), 3, sd.b4);
            raster.setSample(x.intValue(), y.intValue(), 4, sd.b5);
        }

        BoundingBox boundingBox = new ReferencedEnvelope(minx,maxx,miny,maxy, DefaultGeographicCRS.WGS84);


        GridCoverageFactory factory = new GridCoverageFactory();
        GridCoverage2D coverage2D = factory.create("name", raster, boundingBox);

        return coverage2D;
    }

    private class SensorData {

        final int b1;
        final int b2;
        final int b3;
        final int b4;
        final int b5;
        final double x;
        final double y;

        public SensorData(int b1, int b2, int b3, int b4, int b5, double x, double y) {
            this.b1 = b1;
            this.b2 = b2;
            this.b3 = b3;
            this.b4 = b4;
            this.b5 = b5;
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final SensorData other = (SensorData) obj;
            if (this.b1 != other.b1) {
                return false;
            }
            if (this.b2 != other.b2) {
                return false;
            }
            if (this.b3 != other.b3) {
                return false;
            }
            if (this.b4 != other.b4) {
                return false;
            }
            if (this.b5 != other.b5) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 37 * hash + this.b1;
            hash = 37 * hash + this.b2;
            hash = 37 * hash + this.b3;
            hash = 37 * hash + this.b4;
            hash = 37 * hash + this.b5;
            return hash;
        }
    }

}
